package com.xihuanjun.healthcode.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xihuanjun.healthcode.config.SysCache;
import com.xihuanjun.healthcode.dao.ChangeRecordDao;
import com.xihuanjun.healthcode.entity.ChangeRecord;
import com.xihuanjun.healthcode.entity.User;
import com.xihuanjun.healthcode.entity.convert.ChangeRecordConvert;
import com.xihuanjun.healthcode.entity.dto.ChangeRecordDTO;
import com.xihuanjun.healthcode.entity.query.ChangeRecordQuery;
import com.xihuanjun.healthcode.entity.vo.ChangeRecordVO;
import com.xihuanjun.healthcode.entity.vo.UserVO;
import com.xihuanjun.healthcode.excel.ExcelRow;
import com.xihuanjun.healthcode.exception.ServiceException;
import com.xihuanjun.healthcode.service.ChangeRecordService;
import com.xihuanjun.healthcode.service.DownloadRecordService;
import com.xihuanjun.healthcode.service.UserService;
import com.xihuanjun.util.GlobalDataUtils;
import com.xihuanjun.util.IdCardCheck;
import com.xihuanjun.util.UploadUtils;
import lombok.extern.slf4j.Slf4j;
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (ChangeRecord)表服务实现类
 *
 * @author makejava
 * @since 2022-10-25 11:51:09
 */
@Slf4j
@Service("changeRecordService")
@Transactional
public class ChangeRecordServiceImpl extends ServiceImpl<ChangeRecordDao, ChangeRecord> implements ChangeRecordService {

    @Autowired
    ChangeRecordConvert changeRecordConvert;

    @Autowired
    DownloadRecordService downloadRecordService;

    @Autowired
    UserService userService;

    @Autowired
    UploadUtils uploadUtils;

    /**
     * 新增一条变更记录
     *
     * @param dto
     * @return
     */
    @Override
    public boolean save(ChangeRecordDTO dto,long operator) throws ParseException {
        //TODO:上线时解开
//        if(IdCardCheck.check(dto.getIdCard())==false){
//            throw new ServiceException("身份证校验失败");
//        }
        ChangeRecord changeRecord = changeRecordConvert.dto2record(dto);
        changeRecord.setCreateUser(operator);
        changeRecord.setStatus(1);
        this.save(changeRecord);
        return true;
    }

    @Override
    public boolean update(ChangeRecordDTO dto, long operator) {
        ChangeRecord record = changeRecordConvert.dto2record(dto);
        record.setUpdateUser(operator);
        this.updateById(record);
        return true;
    }

    /**
     * 获取一条精确的记录
     *
     * @param id
     * @return
     */
    @Override
    public ChangeRecordVO get(long id) {
        LambdaQueryWrapper wrapper= Wrappers.lambdaQuery(ChangeRecord.class)
                .eq(ChangeRecord::getId,id);
        ChangeRecord one = this.getOne(wrapper);
        if(one!=null){
            ChangeRecordVO changeRecordVO = changeRecordConvert.record2VO(one);
            setUserName(changeRecordVO);
            return changeRecordVO;
        }
        return null;
    }

    @Override
    public IPage<ChangeRecordVO> listByPage(ChangeRecordQuery query) {
        Page<ChangeRecord> pageInfo=new Page<>(query.getPage(),query.getSize());
        OrderItem orderItem = new OrderItem();
        orderItem.setAsc(query.getOrder().equals("asc"));
        orderItem.setColumn(query.getSort());
        pageInfo.getOrders().add(orderItem);
        LambdaQueryWrapper wrapper=Wrappers.lambdaQuery(ChangeRecord.class)
                .eq(query.getStatus()!=null,ChangeRecord::getStatus,query.getStatus())
                .eq(query.getChangeType()!=null,ChangeRecord::getChangeType,query.getChangeType())
                .eq(query.getCreateUser()!=null,ChangeRecord::getCreateUser,query.getCreateUser())
                .like(StringUtils.isNotBlank(query.getName()),ChangeRecord::getName,query.getName())
                .like(StringUtils.isNotBlank(query.getPhone()),ChangeRecord::getPhone,query.getPhone())
                .like(StringUtils.isNotBlank(query.getIdCard()),ChangeRecord::getIdCard,query.getIdCard());
        IPage<ChangeRecord> page = this.page(pageInfo, wrapper);
        IPage<ChangeRecordVO> pageVO = page.convert(changeRecordConvert::record2VO);
        //嵌入创建人
        addCreateUserName(pageVO.getRecords());
        return pageVO;
    }

    private void addCreateUserName(List<ChangeRecordVO> list){
        //获取创建人的id集合
        Set<Long> createUserIds = list.stream().map(o -> o.getCreateUser()).collect(Collectors.toSet());
        //查询这些创建人信息
        LambdaQueryWrapper queryWrapper=Wrappers.lambdaQuery(User.class)
                .in(User::getId,createUserIds);
        List<User> listUser = userService.list(queryWrapper);
        //把创建人信息转换成键值对
        Map<Long, String> mapUser = listUser.stream().collect(Collectors.toMap(User::getId, User::getName));
        //加入到原集合
        list.forEach(record->record.setCreateUserName(mapUser.get(record.getCreateUser())));

    }

    /**
     * 根据身份证号查询未处理数据
     *
     * @param idCard
     * @return
     */
    @Override
    public List<ChangeRecordVO> checkIdCard(String idCard) {
        LambdaQueryWrapper wrapper=Wrappers.lambdaQuery(ChangeRecord.class)
                .eq(ChangeRecord::getIdCard,idCard)
                .eq(ChangeRecord::getStatus,1);
        List list = this.list(wrapper);
        return list;
    }

    /**
     * 根据所传入的记录编号，生成新的全量数据
     *
     * @param ids
     * @return
     */
    @Override
    public String produce(String ids) {
        //查询记录
        List<Long> longIds = Arrays.asList(ids.split(",")).stream().map(Long::parseLong).collect(Collectors.toList());
        List<ChangeRecord> changeRecords = this.listByIds(longIds);

        //遍历所有记录，移动到指定位置
        for (ChangeRecord changeRecord : changeRecords) {
            GlobalDataUtils.setData(changeRecordConvert.record2DTO(changeRecord));
        }
        //生成excel
        String fileName;
        SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
        fileName="数据"+sdf.format(new Date())+".xlsx";
        // 这里 指定文件
        try (ExcelWriter excelWriter = EasyExcel.write(uploadUtils.getSavePath()+ File.separator+ fileName, ExcelRow.class).build()) {
            // 去调用写入,这里我调用了五次，实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面

            // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
            WriteSheet writeSheet = EasyExcel.writerSheet(0, "红码数据").build();
            // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
            excelWriter.write(SysCache.red.stream().map(changeRecordConvert::dto2Excel).collect(Collectors.toList()), writeSheet);

            WriteSheet writeSheet2 = EasyExcel.writerSheet(1, "橙码数据").build();
            // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
            excelWriter.write(SysCache.orange.stream().map(changeRecordConvert::dto2Excel).collect(Collectors.toList()), writeSheet2);

            WriteSheet writeSheet3 = EasyExcel.writerSheet(2, "核实情况").build();
            // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
            excelWriter.write(SysCache.green.stream().map(changeRecordConvert::dto2Excel).collect(Collectors.toList()), writeSheet3);

        }
        //修改记录状态
        List<ChangeRecord> collect = longIds.stream().map(ChangeRecord::new).collect(Collectors.toList());
        collect.stream().forEach(dd->dd.setStatus(2));
        this.updateBatchById(collect);
        //新增下载记录
        downloadRecordService.newDownload(fileName);
        //更新缓存数据
        downloadRecordService.readExcelData(fileName);
        return fileName;
    }

    private void setUserName(ChangeRecordVO vo){
        if(vo.getCreateUser()!=null){
            UserVO createuserVO = userService.get(vo.getCreateUser());
            vo.setCreateUserName(createuserVO.getName());
        }
        if(vo.getUpdateUser()!=null){
            UserVO updateuserVO = userService.get(vo.getUpdateUser());
            vo.setUpdateUserName(updateuserVO.getName());
        }
    }


}

